#include <vector>

#include <Eigen/Geometry>
#include "OpenGL.h"
#include "Camera.h"
#include "Object.h"
#include <QFile>
#include <QTextStream>
#include <QStringList>

using namespace Eigen;

struct Vertex {

    Vector3f coordinates;
    std::vector<int> neighbors;
    Vector2f texcoord;

    Vertex(){}
    Vertex(Vector3f c, std::vector<int>  n){
        coordinates = c;
        neighbors = n;

    }
    void setCoordinates(Vector3f c){
        coordinates = c;
    }
    void setNeighbors(std::vector<int>  n){
        neighbors = n;
    }
};


class Graph {


public:

    std::vector<Vertex> vertices;
    std::vector<Vector3i> edges;

    unsigned int mVertexBufferId;
    unsigned int mIndexBufferId;
    unsigned int mVertexArrayId;

    Graph();

    /* Graph(std::vector<Vertex> vtx) - remplit le tableau de sommets par des coordonnées et d'arretes par des indices
    et initialise les buffers correspondants pour passer ces données à OpenGL par l'appel de fonction iniBuffers()*/

    Graph(std::vector<Vertex> vtx);

    // lecture du graph depuis un fichier
    void loadGraph(char* filepath);

    /*
     crée et remplit dans la même boucle les textures T_cur, T_next, T_nodes, T_edgesList:

    - pour T_cur et T_next les coordonnées x, y, z de sommets simplement s'écrivent dans 3 premiers éléments de texel - RGB - le dernier - la valeur d'alpha est égal 1, mais il peut avoir toutes les valeur, car l'algorithme ne s'en sert pas
    - pour T_nodes: d'abord on affecte le nombre de voisins du sommet correspondant au 3ème élément (4ème aussi vaut 1 comme dans le premier cas), ensuite on prend la position dans la texture après le dernier texel remplit : Tedges_listIndex.
    Ce sera le début de liste de voisins pour le sommet en cours de traitement. Pour chaque texel suivant de Tedges_list on définit le coordonnées dans la texture qui contient les sommets afin de les récuperer lors de calcule:
        - sur CPU on représent une texture comme un tableau 1D mais dans GPU elle est passée comme un tableau 2D, donc on définit les coordonnées dans l'espace 2D:
            - Y: nombre entier de division de nombre de voisins de ce sommet sur la taille de texture 2D (en prenant en compte que la texture est 4 fois plus grande à cause de structure de texels). Cela donne la quantité de lignes remplies entièrement et donc la coordonnée Y
            - X: difference entre le nombre de voisins pour le sommet en cours de traitement et le résultat de multiplication du résultat pour Y sur la taille de matrice. Cela donne le reste: le deplacement dans la derniere ligne qui ne pas remplite en entier et donc la coordonnée X
        - les résultats de calculs précédents dals deux premiers éléments de texel dans le tableau T_nodes correspondant au sommets en cours de traitement
    */
    void fillArrays(GLfloat* T_cur, GLfloat* T_next, GLfloat* T_nodes, GLfloat* T_edgesList);

    // initialisation de buffers avec les coordonnees de sommets et de textures
    void initBuffers();

    void draw(const Camera& camera, Shader& mShader);

    // lrs fonctions pour recuperer l'information sur le graphe
    int getNumVertices();

    // alcule la somme de voisins de tous les sommets de graph (necéssaire pour définir la taille de texture gardant la liste de voisins pour chaque sommet)
    int getNumNeighbors();

    int getVertMatrixDim();
    int getNeighboursMatrixDim();

    // définit les tailles de textures gardant les données et les écrit dans les arguments de fonction
    int getArrayDims(int &verticesDim, int &neighboursDim);

    // affecte les nouvelles coordonnées aux sommets en évitant les à (qui correspondent aux pixels noirs dans la texture lue depuis FBO)
    void updateVertices(GLfloat* T_cur);
};
